#lang racket
(require racket/draw racket/gui)

;PREDEFINED-------------------------------------------------------------------------------------------------------
(define frame (new frame% [label "Drawing Example"]
                   [width 800]
                   [height 650]))
(define canvas (new canvas% [parent frame]))
(define dc (send canvas get-dc))
(send frame show #t)
(sleep/yield 1)
;(send dc draw-line 0 0 30 30)
(define (draw-line p1 p2)
  (let ((x1 (xcor-vect p1))
        (y1 (ycor-vect p1))
        (x2 (xcor-vect p2))
        (y2 (ycor-vect p2)))
    (send dc draw-line x1 y1 x2 y2)))
;VECTOR-----------------------------------------------------------------------------------------------------------
(define (make-vect x y) (cons x y))

(define (xcor-vect v) (car v))

(define (ycor-vect v) (cdr v))

(define (add-vect v1 v2)
  (let ((x1 (car v1))
        (x2 (car v2))
        (y1 (cdr v1))
        (y2 (cdr v2)))
    (make-vect (+ x1 x2) (+ y1 y2))))

(define (sub-vect v1 v2)
  (let ((x1 (car v1))
        (x2 (car v2))
        (y1 (cdr v1))
        (y2 (cdr v2)))
    (make-vect (- x1 x2) (- y1 y2))))

(define (scale-vect s v)
  (let ((x (car v))
        (y (cdr v)))
    (make-vect (* x s) (* y s))))
;SEGMENT----------------------------------------------------------------------------------------------------------
(define (make-segment p1 p2) (cons p1 p2))

(define (start-segment seg) (car seg))

(define (end-segment seg) (cdr seg))
;FRAME-----------------------------------------------------------------------------------------------------------
(define (make-frame origin edge1 edge2)
  (cons origin (cons edge1 edge2)))

(define (origin-frame frame)
  (car frame))

(define (edge1-frame frame)
  (car (cdr frame)))

(define (edge2-frame frame)
  (cdr (cdr frame)))

(define (frame-coord-map frame)
  (lambda (v)
    (add-vect
     (origin-frame frame)
     (add-vect (scale-vect (xcor-vect v)
                           (edge1-frame frame))
               (scale-vect (ycor-vect v)
                           (edge2-frame frame))))))
;EXERCISE---------------------------------------------------------------------------------------------------------
(define (segments->painter segment-list)
  (lambda (frame)
    (for-each
     (lambda (segment)
       (draw-line
        ((frame-coord-map frame) (start-segment segment))
        ((frame-coord-map frame) (end-segment segment))))
     segment-list)))

(define (transform-painter painter origin corner1 corner2)
  (lambda (frame)
    (let ((m (frame-coord-map frame)))
      (let ((new-origin (m origin)))
        (painter
         (make-frame new-origin
                     (sub-vect (m corner1) new-origin)
                     (sub-vect (m corner2) new-origin)))))))

(define (flip-horiz painter)
  (transform-painter painter
                     (make-vect 1 0)
                     (make-vect 0 0)
                     (make-vect 1 1)))

(define (flip-vert painter)
  (transform-painter painter
                     (make-vect 0 1)
                     (make-vect 1 1)
                     (make-vect 0 0)))

(define (rotate90 painter)
  (transform-painter painter
                     (make-vect 0 1)
                     (make-vect 0 0)
                     (make-vect 1 1)))

(define (rotate180 painter)
  (transform-painter painter
                     (make-vect 1 1)
                     (make-vect 0 1)
                     (make-vect 1 0)))

(define (rotate270 painter)
  (transform-painter painter
                     (make-vect 1 0)
                     (make-vect 1 1)
                     (make-vect 0 0)))

(define (beside painter1 painter2)
  (let ((split-point (make-vect 0.5 0.0)))
    (let ((paint-left
           (transform-painter painter1
                              (make-vect 0.0 0.0)
                              split-point
                              (make-vect 0.0 1.0)))
          (paint-right
           (transform-painter painter2
                              split-point
                              (make-vect 1.0 0.0)
                              (make-vect 0.5 1.0))))
      (lambda (frame)
        (paint-left frame)
        (paint-right frame)))))

(define (below painter1 painter2)
  (let ((split-point (make-vect 0.0 0.5)))
    (let ((paint-bottom (transform-painter painter1
                                           split-point
                                           (make-vect 1.0 0.5)
                                           (make-vect 0.0 1.0)))
          (paint-top (transform-painter painter2
                                        (make-vect 0.0 0.0)
                                        (make-vect 1.0 0.0)
                                        split-point)))
      (lambda (frame)
        (paint-top frame)
        (paint-bottom frame)))))

(define (split or1 or2)
  (lambda (painter n)
    (if (= n 0)
        painter
        (let ((smaller ((split or1 or2) painter (- n 1))))
          (or1 painter (or2 smaller smaller))))))

(define (up-split painter n)
  ((split below beside) painter n))

(define (right-split painter n)
  ((split beside below) painter n))

(define (corner-split painter n)
  (if (= n 0)
      painter
      (let ((up (up-split painter (- n 1)))
            (right (right-split painter (- n 1))))
        (let ((top-left up)
              (bottom-right right)
              (corner (corner-split painter (- n 1))))
          (beside (below painter top-left)
                  (below bottom-right corner))))))

(define (square-of-four tl tr bl br)
  (lambda (painter)
    (let ((top (beside (tl painter) (tr painter)))
          (bottom (beside (bl painter) (br painter))))
      (below bottom top))))

(define (square-limit painter n)
  (let ((combine4 (square-of-four flip-vert rotate180
                                  identity flip-horiz)))
    (combine4 (corner-split painter n))))

;(define (right-split painter n)
;  (if (= n 0)
;      painter
;      (let ((smaller (right-split painter (- n 1))))
;        (beside painter (below smaller smaller)))))

;(define (below painter1 painter2)
;  (rotate90 (beside (rotate270 painter1) (rotate270 painter2))))
  
  (define 00p (make-vect 0 0))
  (define 01p (make-vect 0 1))
  (define 10p (make-vect 1 0))
  (define 11p (make-vect 1 1))
  
  (define just-frame (make-frame (make-vect 0 0) (make-vect 600 0) (make-vect 0 600)))
  ;a
  (define square-list (list (make-segment 00p 01p)
                            (make-segment 01p 11p)
                            (make-segment 11p 10p)
                            (make-segment 10p 00p)))
  
  
  (define arrow-list (append square-list (list (make-segment (make-vect 0.5 0) (make-vect 0.5 1))
                                               (make-segment (make-vect 0 0.9) (make-vect 0.55 0.9))
                                               (make-segment (make-vect 0 0.8) (make-vect 0.55 0.8)))))
  
  ((square-limit (segments->painter arrow-list) 4) just-frame)